/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2025. All rights reserved.
 *
 */

import { hvigorCore, Json5Reader } from '@ohos/hvigor';
import fse from 'fs-extra';
import path from 'path';

import { BuildArtifactExtension, BuildDirConst } from '../const/build-directory-const.js';
import { CommonConst, DefaultTargetConst } from '../const/common-const.js';
import { ModuleType } from '../enum/module-type-enum.js';
import { ProjectModelImpl } from '../model/project/project-model-impl.js';
import { DependencyManager } from '../project/dependency/dependency-manager.js';
import { OhosLogger } from '../utils/log/ohos-logger.js';
import { getSignRemoteHspMetadata } from '../utils/remote-hsp-utils.js';

import { TaskNames } from './common/task-names.js';
import { TargetTaskService } from './service/target-task-service.js';
import { OhosHapTask } from './task/ohos-hap-task.js';
import { deviceCoverageQueueCenter } from './device-coverage-queue-center.js';

/**
 * 命令行生成ohos测试覆盖率报告
 */
export class GenerateDeviceCoverage extends OhosHapTask {
  private readonly _log = OhosLogger.getLogger(GenerateDeviceCoverage.name);

  constructor(taskService: TargetTaskService) {
    super(taskService, TaskNames.Task.GENERATE_DEVICE_COVERAGE);
  }

  protected async doTaskAction(): Promise<void> {
    if (this.targetData.getTargetName() === CommonConst.OHOS_TEST) {
      return;
    }
    if (!this.targetService.getModuleService().findTargetDataByName(DefaultTargetConst.OHOS_TEST_TARGET)) {
      this._log.printErrorExit(
        'NO_TARGET_OHOSTEST',
        [this.moduleModel.getName(), CommonConst.ON_DEVICE_TEST],
        [[this.moduleModel.getName()]]
      );
    }
    const ohosTestPath = path.resolve(path.resolve(this.moduleModel.getProjectDir(), BuildDirConst.SRC), DefaultTargetConst.OHOS_TEST_TARGET);
    if (!fse.existsSync(ohosTestPath)) {
      this._log.printErrorExit(
        'OHOSTEST_PATH_NOT_EXIST',
        [ohosTestPath, CommonConst.ON_DEVICE_TEST],
        [[ohosTestPath]]
      );
    }
    const remoteHspObj = getSignRemoteHspMetadata(this.service, this.targetService.getTargetData().getProduct().name);
    let remoteHspPathList: string[] = [];
    if (remoteHspObj) {
      remoteHspPathList = remoteHspObj.map((obj) => obj.hspPath);
    }

    const projectDir = this.service.getProjectModel().getProjectDir();
    const moduleNodeDir = this.moduleModel.getModule().getNodeDir();
    const moduleJsonPath = path.resolve(projectDir, moduleNodeDir, `src/ohosTest/${CommonConst.MODULE_JSON5}`);
    if (!fse.existsSync(moduleJsonPath)) {
      this._log.printErrorExit(
        'OHOSTEST_MODULE_JSON_NOT_EXIST',
        [moduleJsonPath],
        [[moduleJsonPath]]
      );
    }
    const moduleJsonObj = Json5Reader.getJson5Obj(moduleJsonPath);
    const testInstrumentParam = {
      toolchainsPath: this.sdkInfo.getBasePath(),
      projectPath: (this.projectModel as ProjectModelImpl).getProjectDir(),
      modulePath: this.pathInfo.getModulePath(),
      bundleName: this.targetData.getProduct().bundleName ?? this.projectModel.getDefaultBundleName(),
      bundleType: this.targetData.getProduct().bundleType ?? this.projectModel.getBundleType(),
      coverage: hvigorCore.getExtraConfig().get(CommonConst.OHOS_TEST_COVERAGE) === 'true',
      logger: this._log,
      scope: hvigorCore.getExtraConfig().get(CommonConst.OHOS_TEST_COVERAGE_SCOPE) ?? '',
      testModuleName: moduleJsonObj.module.name,
      targetHapPath: this.getOutputPackagePath(),
      testHapPath: path.resolve(
        this.pathInfo.getModuleBuildOhosTestOutputPath(),
        this.targetData.getModuleTargetOutputFileName('', true, BuildArtifactExtension.DOT_HAP, '', 'ohosTest'),
      ),
      dependenciesPaths: [...this.getDependenciesPaths(), ...remoteHspPathList].reverse(),
    };

    // 添加测试框架提供的方法到队列中
    await deviceCoverageQueueCenter.executeProxy(testInstrumentParam);
  }

  getOutputPackagePath() {
    if (this.service.getModuleModel().getModuleType() === ModuleType.Shared) {
      return path.resolve(
        this.pathInfo.getModuleBuildOutputPath(),
        this.targetData.getModuleTargetOutputFileName(this.targetName, true, BuildArtifactExtension.DOT_HSP),
      );
    } else if (this.service.getModuleModel().getModuleType() === ModuleType.Entry || this.service.getModuleModel().getModuleType() === ModuleType.Feature) {
      return path.resolve(
        this.pathInfo.getModuleBuildOutputPath(),
        this.targetData.getModuleTargetOutputFileName(this.targetName, true, BuildArtifactExtension.DOT_HAP),
      );
    } else {
      const artifactName = this.targetData.getTargetOpt().output?.artifactName;
      const outputName = artifactName ? `${artifactName}` : `${this.moduleName}`;
      return path.resolve(this.pathInfo.getModuleBuildOutputPath(), `${outputName}.har`);
    }
  }

  initTaskDepends(): void {
    // no task
  }

  protected getDependenciesPaths(): string[] {
    const set = new Set();
    const deepNpmDependencies = new DependencyManager(false, this.moduleModel, this.projectModel).collectAllHspDependencies();
    deepNpmDependencies.forEach((hspInfo) => {
      const hspName = hspInfo[0];
      for (const target of [this.targetService.getTargetData().getTargetName(), DefaultTargetConst.DEFAULT_TARGET]) {
        const hspTargetData = this.targetService.getTargetData().findTargetDataByName(hspName, target);
        if (hspTargetData === undefined) {
          continue;
        }
        set.add(
          path.resolve(
            hspTargetData.getPathInfo().getModuleBuildOutputPath(),
            hspTargetData.getModuleTargetOutputFileName('', true, BuildArtifactExtension.DOT_HSP),
          ),
        );
      }
    });
    return Array.from(set) as string[];
  }
}
